package pso;

import java.io.IOException;
import java.util.ArrayList;

import mlp.MlpPso;

import pso.FileWrite;

import function.Function;

public class PSO_Global {

	private pso.Function f;
	private int psoSize;
	private int numberIterations;
	private ArrayList<Particle> population;
	private double [] globalBestPosition = null;
	private double gBest;
	private MlpPso validacao;
	
	private StringBuffer bfInterval = new StringBuffer();
	private StringBuffer bfGlobal   = new StringBuffer();
	private String expName;
	
	public PSO_Global(pso.Function f, int psoSize, int numberIterations, String expName){
		this.f = f;
		this.psoSize = psoSize;
		this.numberIterations = numberIterations;
		this.gBest = Double.MAX_VALUE;
		this.expName = new String(expName);
		this.validacao = new MlpPso(".\\seedValidacao.txt");
	}
	
	
	public double[] run(){
		
		int iteration = 0;
		this.createPopulation();
		

		double anterior = 0;
		while(iteration < this.numberIterations){

			updatePersonalBestPosition();
			updateGlobalBestPSO();	
			updateVelocity(this.globalBestPosition, iteration);
			updatePosition();
			if (iteration % 1000 == 0){
				double valor = validacao.calculate(this.globalBestPosition);
					
				
				System.out.println("Treino = " + this.gBest);				
				System.out.println("Validacao = " + valor );
				
				if (anterior * 0.90 < valor ){
					System.out.println("Valor anterior  = "  + anterior + " Valor atual = " + valor);
					return this.globalBestPosition;
				}
				anterior = valor;
			}
			
			iteration++;

		}
		

		return this.globalBestPosition;
	}
	
	
	//criando as populacoes
	private void createPopulation() {
		this.population = new ArrayList<Particle>();
		for (int i = 0; i < this.psoSize; i++) {
			population.add(new Particle(this.f,i));
		}
	}
		
		
	private void updateGlobalBestPSO(){
		for (Particle particle : population) {
			if(this.globalBestPosition == null)
				this.globalBestPosition = particle.getPersonalBestPosition().clone();
			
			if( f.calculate(particle.getPersonalBestPosition()) < f.calculate(this.globalBestPosition) ){
				this.globalBestPosition = particle.getPersonalBestPosition().clone();
			}
			
			this.gBest = f.calculate(this.globalBestPosition);
		}	
	}
	
	private void updatePersonalBestPosition(){
		for (Particle particle : population) {
			particle.calculatePersonalBestPosition();
		}
	}
	
	private void updateVelocity(double [] bestPositionSwarm, int iteration){
		for (Particle particle : population) {
			particle.calculateVelocity(bestPositionSwarm, iteration, this.numberIterations);
		}
	}
	
	private void updatePosition(){
		for (Particle particle : population) {
			particle.calculatePosition();
		}
	}
	
	private void printBestPoint(int iteration , StringBuffer bestFitnesseByInterval , StringBuffer bestFitnessGlobal) {
		double bestFitness = Double.MAX_VALUE;
		double fitnessParticula;
		
		for (Particle particle : this.population) {
			fitnessParticula = this.f.calculate(particle.getnBest());
			if (fitnessParticula < bestFitness){
				bestFitness = fitnessParticula;
			}
			
			if (iteration % ((this.numberIterations-1)/20) == 0){
				bestFitnesseByInterval.append(bestFitness + "\t" + iteration/100 + "\t" + this.expName);
				bestFitnesseByInterval.append("\n");
			}
			
		}
		
		bestFitnessGlobal.append(bestFitness + ", ");
		
		
	}
	
	private void writeInFile(StringBuffer bf , String filename){
		try {
			FileWrite.writeInFile(bf.toString(), "./resultadosPSO//" + filename);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void clearBuffers(){
		this.bfGlobal.delete(0, this.bfGlobal.length());
		this.bfInterval.delete(0, this.bfInterval.length());
	}
	
}
